package com.tanhua.server.service;

import com.alibaba.fastjson.JSON;
import com.tanhua.commons.exception.TanHuaException;
import com.tanhua.commons.templates.FaceTemplate;
import com.tanhua.commons.templates.HuanXinTemplate;
import com.tanhua.commons.templates.OssTemplate;
import com.tanhua.commons.templates.SmsTemplate;
import com.tanhua.domain.db.User;
import com.tanhua.domain.db.UserInfo;
import com.tanhua.domain.vo.ErrorResult;
import com.tanhua.domain.vo.UserInfoVo;
import com.tanhua.dubbo.api.UserApi;
import com.tanhua.dubbo.api.UserInfoApi;
import com.tanhua.server.utils.JwtUtils;
import com.tanhua.server.utils.ThreadLocalUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 用户管理业务层
 */
@Service
@Slf4j
public class UserService {

    //    订阅userInfo服务接口
    @Reference
    private UserInfoApi userInfoApi;
    //    订阅对应的接口服务
    @Reference
    private UserApi userApi;
    //     注入ossTemplate对象
    @Autowired
    private OssTemplate ossTemplate;
    //    注入redisTemplate
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    //    注入smsTemplate对象 （用于发送短信
    @Autowired
    private SmsTemplate smsTemplate;
    //    注入验证码前缀固定信息
    @Value("${tanhua.sms.redisValidateCodeKeyPrefix}")
    private String prefix;
    //    注入jwtUtils对象
    @Autowired
    private JwtUtils jwtUtils;
    //    注入人脸识别模板对象
    @Autowired
    private FaceTemplate faceTemplate;
    //    注入ThreadLocalUtils对象
    @Autowired
    private ThreadLocalUtils threadLocalUtils;
    //    注入HuanXinTemplate对象
    @Autowired
    private HuanXinTemplate huanXinTemplate;
    //    注入RockerMQTemplate
    @Autowired
    private RocketMQTemplate rocketMQTemplate;


    /**
     * 根据手机号查询用户
     *
     * @param mobile
     * @return
     */
    public ResponseEntity findByMobile(String mobile) {
        User user = userApi.findByMobile(mobile);
        return ResponseEntity.ok(user);
    }

    /**
     * 新增用户
     *
     * @param mobile
     * @return
     */
    public ResponseEntity saveUser(String mobile, String password) {
        User user = new User();
        user.setMobile(mobile);
        user.setPassword(password);
        userApi.save(user);
        return ResponseEntity.ok(user.getId());
    }

    /**
     * 发送验证码信息(使用硬编码方式 暂不使用阿里云)
     *
     * @param phone
     */
    public void sendValidateCode(String phone) {
        try {
            //使用RedisTemplate模板创建一个对象
            ValueOperations<String, String> ops = redisTemplate.opsForValue();
            //前缀
            String nPhone = prefix + phone;
            log.info("[正在验证是否在30秒发送过验证码" + nPhone + "]");
            //判断手机号在redis中是否存在
            if (StringUtils.isNotEmpty(ops.get(nPhone))) {
                throw new TanHuaException(ErrorResult.duplicate());
            }
            //生成6位数的随机验证码
            String randomNumeric = RandomStringUtils.randomNumeric(6);
            //将验证码存入到redis中  key:手机号 value:验证码 时间为30秒失效
            ops.set(nPhone, "111111", 30, TimeUnit.SECONDS);
            //当前不使用阿里云发送 所以收不到短信 我们可以在控制台输出一下
            log.info("[手机号]：" + nPhone + "[生成的验证码]：" + 111111);
        } catch (TanHuaException e) {
            //抓取异常
            throw new TanHuaException(ErrorResult.error());
        }
    }

    /**
     * 校验验证码
     */
    public Map loginVerification(String phone, String verificationCode) {
        String type="01";//设置默认类型为登录
        //将手机号拼接
        String nPhone = prefix + phone;
        //将拼接的手机号去redis中查找是否存在这个键
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        String yzm = ops.get(nPhone);
        //如果不存在那么就之间抛出异常
        if (yzm == null) {
            log.debug("验证码失效了~");
            throw new TanHuaException(ErrorResult.loginError());
        }
        log.debug("用户输入的验证码：" + verificationCode + "--手机号：" + phone);
        log.debug("从redis中获取的临时验证码：" + verificationCode)        ;
        //如果验证码和redis中的验证码不正确 那么抛出异常
        if (!yzm.equals(verificationCode)) {
            log.debug("验证码不正确~");
            throw new TanHuaException(ErrorResult.validateCodeError());
        }
        //调用服务接口 根据用户手机号查询是否存在
        User byMobile = userApi.findByMobile(phone);
        //如果不存在 调用服务接口向数据库插入一条数据 然后将isNew状态更改为true
        //设置isNew对象 这个参数代表是否要跳转到信息补全界面
        boolean isNew = false;
        if (byMobile == null) {
        //新建一个对象 将对象地址值赋值给byMobile
            byMobile = new User();
            log.debug("查看对象是否存在日期" + byMobile.toString());
            byMobile.setMobile(phone);
        //初始的密码为手机号码的后6位
            byMobile.setPassword(DigestUtils.md5Hex(phone.substring(phone.length() - 6)));
        //调用服务接口插入数据 返回用户的id
            Long save = userApi.save(byMobile);
        //将返回的ID设置到byMobile对象
            byMobile.setId(save);
        //修改isNew状态
            isNew = true;
        //使用环信通讯注册用户
            huanXinTemplate.register(save);
            type="02";//修改为注册
        }
        //发送消息队列
        Map<String, Object> message = new HashMap<>();
        message.put("userId",byMobile.getId());
        message.put("type",type);
        message.put("logTime",new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        rocketMQTemplate.convertAndSend("ysx_log_Topic",message);
        System.out.println("---------------------发送消息队列---------------------------");
        log.debug("欢迎登录：" + byMobile);
        //调用jwt工具类 生成token
        String token = jwtUtils.createJWT(phone, byMobile.getId());
        //序列化user对象
        String userString = JSON.toJSONString(byMobile);
        //将Token添加一个前缀 存入到redsi中 值为user的json形式
        ops.set("TOKEN_" + token, userString, 1, TimeUnit.DAYS);
        // 返回map集合  map集合里面有：token 和isNew这两个参数
        Map<String, Object> map = new HashMap<String, Object>();
        log.debug("签发token~" + token);
        map.put("token", token);
        map.put("isNew", isNew);
        //删除redis缓存 防止重复使用
        redisTemplate.delete(nPhone);
        log.debug("正在删除redis缓存~");
        // 返回数据
        return map;
    }

    /**
     * 首次登录个人信息完善
     */
    public void loginReginfo(UserInfo userInfo) {
        //使用ThreadLoadUtils对象的get方法获取到id
        Long id = threadLocalUtils.getUserId();
        //设置到userinfo中 作为添加的条件或者后期更新的条件
        userInfo.setId(id);
        //调用方法 传入userinfo对象 返回一个受影响的结果
        userInfoApi.saveInfo(userInfo);
    }

    /**
     * 人脸识别
     *
     * @param headPhoto
     * @param
     * @return
     */
    public void faceRecognition(MultipartFile headPhoto) {
        try {
            User user = threadLocalUtils.getUser();
//       获取到文件对象的源文件名
            String filename = headPhoto.getOriginalFilename();
//        获取到文件对象的字节流
            InputStream is = headPhoto.getInputStream();
//        使用faceTemplate进行人脸识别（接口有问题 不调用）
//        boolean detect = faceTemplate.detect(headPhoto.getBytes());
            log.debug("—————正在进行人脸识别—————");
            Boolean detect = true;
            if (!detect) {
                log.debug("人脸识别失败~");
                throw new TanHuaException(ErrorResult.faceError());
            }
//        使用阿里云ossTemplate模板对象上传图片 返回图片地址
            String avatar = ossTemplate.upload(filename, is);
//        将图片地址和userId设置到对象userInfo
            UserInfo userInfo = new UserInfo();
            userInfo.setAvatar(avatar);
            userInfo.setId(user.getId());
//        调用UserInfoAPi方法 传入userinfo对象
            userInfoApi.updateInfo(userInfo);
        } catch (Exception e) {
            throw new TanHuaException(ErrorResult.picUploadFailed());
        }
    }


}